// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package reflect

import (
	"internal/abi"
	"internal/goarch"
	"internal/goexperiment"
	"unsafe"
)

// 这些变量由该文件中的寄存器分配
// 算法使用。
// 
// 应该小心修改它们（没有其他反映代码
// 可能正在执行），并且通常仅在测试此包时修改
// 。
// 
// 它们的设置不应高于其内部/abi 
// 常量对应项，因为系统依赖于一个至少足以容纳系统支持的
// 结构。
// 寄存器的
// 
// 目前它们被设置为零，因为使用实际的
// 常量将破坏
// 用于调用函数的工具链的每个部分（例如go test，或任何使用文本/模板的
// ）。当前值
// 注释出来的值应该是实际值，一旦
// 我们准备好在任何地方使用寄存器ABI。
var (
	intArgRegs   = abi.IntArgRegs * goexperiment.RegabiArgsInt
	floatArgRegs = abi.FloatArgRegs * goexperiment.RegabiArgsInt
	floatRegSize = uintptr(abi.EffectiveFloatRegSize * goexperiment.RegabiArgsInt)
)

// abiStep代表ABI“指令”每条指令
// 描述了如何在内存中的Go值
// 和调用帧之间进行转换的一部分。
type abiStep struct {
	kind abiStepKind

	// 偏移量和大小一起描述了Go值在内存中的一部分。
	offset uintptr
	size   uintptr // 部分的字节大小

	// 这些字段描述翻译的ABI端。
	stkOff uintptr // 堆栈偏移量，当种类==abiStepStack 
	ireg   int     // 整数寄存器索引时使用，当种类==abiStepIntReg或种类==ABISTEPOINTER 
	freg   int     // FP寄存器索引时使用，当种类==ABISTEPFOLATREG 
}

// ABISTEPTKIND是abiStep指令的“操作码”。
type abiStepKind int

const (
	abiStepBad      abiStepKind = iota
	abiStepStack                // copy to/from stack 
	abiStepIntReg               // copy to/from integer寄存器
	abiStepPointer              // copy pointer to/from integer寄存器
	abiStepFloatReg             // copy to/from FP寄存器
)

// abiSeq表示从一系列映射复制
// 。调用帧的值（对于调用参数）
// 反之亦然（对于调用结果）。
// 
// 应该通过调用其addArg方法来填充abiSeq。
type abiSeq struct {
	// 步骤是一组指令。
	// 
	// 这些指令按整个参数组合在一起，
	// 指令的起始索引
	// 第i个Go值在valueStart中可用。
	// 
	// 例如，如果此abiSeq表示传递给函数的3个参数
	// 则第二个参数的步骤
	// 从步骤[valueStart[1]开始。
	// 
	// 因为reflect在不同的
	// 值中接受Go参数，并且每个值都是单独存储的，所以开始一个新参数的每个abiStep 
	// 将有其偏移量
	// 字段==0。
	steps      []abiStep
	valueStart []int

	stackBytes   uintptr // 使用的堆栈空间
	iregs, fregs int     // 使用的寄存器
}

func (a *abiSeq) dump() {
	for i, p := range a.steps {
		println("part", i, p.kind, p.offset, p.size, p.stkOff, p.ireg, p.freg)
	}
	print("values ")
	for _, i := range a.valueStart {
		print(i, " ")
	}
	println()
	println("stack", a.stackBytes)
	println("iregs", a.iregs)
	println("fregs", a.fregs)
}

// stepsForValue返回ABI指令，用于翻译
// 第i个Go参数或返回值，由该
// abiSeq表示为Go ABI。
func (a *abiSeq) stepsForValue(i int) []abiStep {
	s := a.valueStart[i]
	var e int
	if i == len(a.valueStart)-1 {
		e = len(a.steps)
	} else {
		e = a.valueStart[i+1]
	}
	return a.steps[s:e]
}

// addArg使用类型为t的新Go值扩展abiSeq。
// 
// 如果该值是堆栈分配的，则返回描述该转换的单个
// abiStep，否则返回零。
func (a *abiSeq) addArg(t *rtype) *abiStep {
	// 我们总是在添加一个新值，所以请先添加。
	pStart := len(a.steps)
	a.valueStart = append(a.valueStart, pStart)
	if t.size == 0 {
		// 如果参数类型的大小为零，则
		// 为了优雅地降级为ABI0，我们需要
		// 来堆栈分配此类型。原因是
		// 虽然零大小的类型不占用
		// 堆栈上的空间，但它们确实会导致下一个参数对齐。
		// 所以就在这里这么做，但不必麻烦实际
		// 为它生成一个新的ABI步骤（没有什么需要
		// 实际复制）。
		// 
		// 在
		// 重新分配的递归情况下，我们无法处理此问题，因为
		// 非零大小结构的零大小*字段*不会导致它被
		// 堆栈分配。所以我们需要一个特例在顶部。
		a.stackBytes = align(a.stackBytes, uintptr(t.align))
		return nil
	}
	// 保存一份“a”的副本，以便在
	// 寄存器分配失败时回滚。
	aOld := *a
	if !a.regAssign(t, 0) {
		// 寄存器分配失败。回滚所有更改
		// 和堆栈分配。
		*a = aOld
		a.stackAssign(t.size, uintptr(t.align))
		return &a.steps[len(a.steps)-1]
	}
	return nil
}

// addRcvr通过一个新的方法调用
// 根据接口调用约定的接收器。
// 
// 如果接收器是堆栈分配的，则返回单个
// abiStep描述该转换，否则返回零。
// 如果接收器是指针，则返回true。
func (a *abiSeq) addRcvr(rcvr *rtype) (*abiStep, bool) {
	// 接收者总是一个字。
	a.valueStart = append(a.valueStart, len(a.steps))
	var ok, ptr bool
	if ifaceIndir(rcvr) || rcvr.pointers() {
		ok = a.assignIntN(0, goarch.PtrSize, 1, 0b1)
		ptr = true
	} else {
		// TODO（mknyszek）：这种情况可能吗？
		// 接口数据工作从不包含非指针
		// 值。这个案例是从reflect包中较旧的代码
		// 复制过来的，reflect包只有条件地添加了
		// 一个指向reflect的指针位。（价值）。调用堆栈帧的
		// GC位图。
		ok = a.assignIntN(0, goarch.PtrSize, 1, 0b0)
		ptr = false
	}
	if !ok {
		a.stackAssign(goarch.PtrSize, goarch.PtrSize)
		return &a.steps[len(a.steps)-1], ptr
	}
	return nil, ptr
}

// regAssign尝试为
// 类型t的值保留参数寄存器，存储在某个偏移量。
// 
// 返回赋值是否成功，但
// 保留对a.steps所做的任何更改，因此调用方
// 如果失败，必须通过调整a.steps来撤销该工作。
// 
// 此方法以及assign*方法代表
// Go ABI的完整寄存器分配算法。
func (a *abiSeq) regAssign(t *rtype, offset uintptr) bool {
	switch t.Kind() {
	case UnsafePointer, Pointer, Chan, Map, Func:
		return a.assignIntN(offset, t.size, 1, 0b1)
	case Bool, Int, Uint, Int8, Uint8, Int16, Uint16, Int32, Uint32, Uintptr:
		return a.assignIntN(offset, t.size, 1, 0b0)
	case Int64, Uint64:
		switch goarch.PtrSize {
		case 4:
			return a.assignIntN(offset, 4, 2, 0b0)
		case 8:
			return a.assignIntN(offset, 8, 1, 0b0)
		}
	case Float32, Float64:
		return a.assignFloatN(offset, t.size, 1)
	case Complex64:
		return a.assignFloatN(offset, 4, 2)
	case Complex128:
		return a.assignFloatN(offset, 8, 2)
	case String:
		return a.assignIntN(offset, goarch.PtrSize, 2, 0b01)
	case Interface:
		return a.assignIntN(offset, goarch.PtrSize, 2, 0b10)
	case Slice:
		return a.assignIntN(offset, goarch.PtrSize, 3, 0b001)
	case Array:
		tt := (*arrayType)(unsafe.Pointer(t))
		switch tt.len {
		case 0:
			// 没有要分配的内容，因此不要修改
			// a.步骤，但要成功，以便调用方不
			// 尝试堆栈分配此值。
			return true
		case 1:
			return a.regAssign(tt.elem, offset)
		default:
			return false
		}
	case Struct:
		st := (*structType)(unsafe.Pointer(t))
		for i := range st.fields {
			f := &st.fields[i]
			if !a.regAssign(f.typ, offset+f.offset()) {
				return false
			}
		}
		return true
	default:
		print("t.Kind == ", t.Kind(), "\n")
		panic("unknown type kind")
	}
	panic("unhandled register assignment path")
}

// assignIntN为寄存器分配n个值，每个“大小”字节都大，
// 从内存中[offset，offset+n*size]处的数据。
// /[offset+i*size，offset+（i+1）处的每个值*i<n的大小）分配给
// 下一个n整数寄存器。
// 
// ptrMap中的第i位指示第i个值是否为指针。
// n必须小于等于8。返回赋值是否成功。
func (a *abiSeq) assignIntN(offset, size uintptr, n int, ptrMap uint8) bool {
	if n > 8 || n < 0 {
		panic("invalid n")
	}
	if ptrMap != 0 && size != goarch.PtrSize {
		panic("non-empty pointer map passed for non-pointer-size values")
	}
	if a.iregs+n > intArgRegs {
		return false
	}
	for i := 0; i < n; i++ {
		kind := abiStepIntReg
		if ptrMap&(uint8(1)<<i) != 0 {
			kind = abiStepPointer
		}
		a.steps = append(a.steps, abiStep{
			kind:   kind,
			offset: offset + uintptr(i)*size,
			size:   size,
			ireg:   a.iregs,
		})
		a.iregs++
	}
	return true
}

// assignFloatN将n个值分配给寄存器，每个“大小”字节都很大，
// 从内存中[offset，offset+n*size]处的数据中。i<n时，
// /[offset+i*size，offset+（i+1）*size]处的每个值被分配给
// 接下来的n个浮点寄存器。
// 
// 返回分配是否成功。
func (a *abiSeq) assignFloatN(offset, size uintptr, n int) bool {
	if n < 0 {
		panic("invalid n")
	}
	if a.fregs+n > floatArgRegs || floatRegSize < size {
		return false
	}
	for i := 0; i < n; i++ {
		a.steps = append(a.steps, abiStep{
			kind:   abiStepFloatReg,
			offset: offset + uintptr(i)*size,
			size:   size,
			freg:   a.fregs,
		})
		a.fregs++
	}
	return true
}

// stackAssign字节
// 大，与堆栈对齐。
// 
// 不应直接调用；改用addArg。
func (a *abiSeq) stackAssign(size, alignment uintptr) {
	a.stackBytes = align(a.stackBytes, alignment)
	a.steps = append(a.steps, abiStep{
		kind:   abiStepStack,
		offset: 0, // 仅用于整个参数，因此内存偏移量为0。
		size:   size,
		stkOff: a.stackBytes,
	})
	a.stackBytes += size
}

// abiDesc描述函数或方法的ABI。
type abiDesc struct {
	// call和ret表示Go函数的调用和返回路径的转换步骤。这些字段描述为调用分配的堆栈空间。StackCallArgsize是
	call, ret abiSeq

	// 为参数而非返回值保留的空间量。retOffset 
	// 是返回值开始的偏移量，
	// 溢出是在
	// reflectcall的堆栈帧中发生抢占时溢出参数寄存器所保留的额外空间的字节大小。
	stackCallArgsSize, retOffset, spill uintptr

	// stackPtrs是一个位图，指示ABI堆栈空间（堆栈分配的
	// args+返回值）中的每个字是否为指针。使用
	// 作为堆栈空间的堆指针位图
	// 传递给reflectcall。
	stackPtrs *bitVector

	// inRegPtrs是一个位图，其第i位指示
	// 第i个整型参数寄存器是否包含一个指针。由makeFuncStub和methodValueCall 
	// 使用，使结果指针对GC可见。
	// 
	// outRegPtrs是相同的，但用于结果值。
	// 由reflectcall使用，以使结果指针对GC可见。
	inRegPtrs, outRegPtrs abi.IntArgRegBitmap
}

func (a *abiDesc) dump() {
	println("ABI")
	println("call")
	a.call.dump()
	println("ret")
	a.ret.dump()
	println("stackCallArgsSize", a.stackCallArgsSize)
	println("retOffset", a.retOffset)
	println("spill", a.spill)
	print("inRegPtrs:")
	dumpPtrBitMap(a.inRegPtrs)
	println()
	print("outRegPtrs:")
	dumpPtrBitMap(a.outRegPtrs)
	println()
}

func dumpPtrBitMap(b abi.IntArgRegBitmap) {
	for i := 0; i < intArgRegs; i++ {
		x := 0
		if b.Get(i) {
			x = 1
		}
		print(" ", x)
	}
}

func newAbiDesc(t *funcType, rcvr *rtype) abiDesc {
	// 我们需要在框架中为这个参数添加空间，这样它就可以将参数溢出到框架中。
	// 
	// 这个空间的大小就是每个寄存器分配类型的大小
	// 的总和。
	// 
	// TODO（mknyszek）：当我们不再有
	// 呼叫方保留的溢出空间时，删除此选项。
	spill := uintptr(0)

	// 为堆栈参数计算gc程序和堆栈位图
	stackPtrs := new(bitVector)

	// 计算堆栈帧指针位图，并为参数注册
	// 指针位图。
	inRegPtrs := abi.IntArgRegBitmap{}

	// 计算输入参数的abiSeq。
	var in abiSeq
	if rcvr != nil {
		stkStep, isPtr := in.addRcvr(rcvr)
		if stkStep != nil {
			if isPtr {
				stackPtrs.append(1)
			} else {
				stackPtrs.append(0)
			}
		} else {
			spill += goarch.PtrSize
		}
	}
	for i, arg := range t.in() {
		stkStep := in.addArg(arg)
		if stkStep != nil {
			addTypeBits(stackPtrs, stkStep.stkOff, arg)
		} else {
			spill = align(spill, uintptr(arg.align))
			spill += arg.size
			for _, st := range in.stepsForValue(i) {
				if st.kind == abiStepPointer {
					inRegPtrs.Set(st.ireg)
				}
			}
		}
	}
	spill = align(spill, goarch.PtrSize)

	// 仅从输入参数，我们现在就知道了
	// StackCallArgSize和retOffset。
	stackCallArgsSize := in.stackBytes
	retOffset := align(in.stackBytes, goarch.PtrSize)

	// 计算堆栈帧指针位图，并为返回值注册
	// 指针位图。
	outRegPtrs := abi.IntArgRegBitmap{}

	// 计算输出参数的abiSeq。
	var out abiSeq
	// 堆栈分配的返回值与寄存器的参数不共享
	// 空间，所以我们需要在这里插入堆栈偏移量。
	// 通过人工扩展stackBytes来伪造它，方法是通过
	// 返回偏移量。
	out.stackBytes = retOffset
	for i, res := range t.out() {
		stkStep := out.addArg(res)
		if stkStep != nil {
			addTypeBits(stackPtrs, stkStep.stkOff, res)
		} else {
			for _, st := range out.stepsForValue(i) {
				if st.kind == abiStepPointer {
					outRegPtrs.Set(st.ireg)
				}
			}
		}
	}
	// 撤销之前的伪造，以确保stackBytes 
	// 准确无误。
	out.stackBytes -= retOffset
	return abiDesc{in, out, stackCallArgsSize, retOffset, spill, stackPtrs, inRegPtrs, outRegPtrs}
}

// intFromReg从reg加载argSize大小的整数，并将其放置到。
// 
// argSize必须为非零、适合于寄存器且为二的幂。
func intFromReg(r *abi.RegArgs, reg int, argSize uintptr, to unsafe.Pointer) {
	memmove(to, r.IntRegArgAddr(reg, argSize), argSize)
}

// intToReg加载一个argSize大小的整数，并将其存储到reg。
// 
// argSize必须为非零、适合于寄存器且为二的幂。
func intToReg(r *abi.RegArgs, reg int, argSize uintptr, from unsafe.Pointer) {
	memmove(r.IntRegArgAddr(reg, argSize), from, argSize)
}

// floatFromReg从r中的寄存器表示中加载浮点值。
// 
// argSize必须为4或8。
func floatFromReg(r *abi.RegArgs, reg int, argSize uintptr, to unsafe.Pointer) {
	switch argSize {
	case 4:
		*(*float32)(to) = archFloat32FromReg(r.Floats[reg])
	case 8:
		*(*float64)(to) = *(*float64)(unsafe.Pointer(&r.Floats[reg]))
	default:
		panic("bad argSize")
	}
}

// floatToReg在r中的寄存器表示中存储浮点值。
// 
// argSize必须为4或8。
func floatToReg(r *abi.RegArgs, reg int, argSize uintptr, from unsafe.Pointer) {
	switch argSize {
	case 4:
		r.Floats[reg] = archFloat32ToReg(*(*float32)(from))
	case 8:
		r.Floats[reg] = *(*uint64)(from)
	default:
		panic("bad argSize")
	}
}
